package net.hn.hnms.sys.common.core.utils;

import cn.hutool.core.date.DateUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.time.DateFormatUtils;

import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.temporal.TemporalAdjusters;
import java.util.*;

/**
 * 时间工具类
 *
 * @author ruoyi
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {

    public static final String YYYY = "yyyy";

    public static final String YYYY_MM = "yyyy-MM";

    public static final String YYYY_MM_DD = "yyyy-MM-dd";

    public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";

    public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

    private static final String[] PARSE_PATTERNS = {
            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};

    /**
     * 获取当前Date型日期
     *
     * @return Date() 当前日期
     */
    public static Date getNowDate() {
        return new Date();
    }

    /**
     * 获取当前日期, 默认格式为yyyy-MM-dd
     *
     * @return String
     */
    public static String getDate() {
        return dateTimeNow(YYYY_MM_DD);
    }

    public static String getTime() {
        return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
    }

    public static String dateTimeNow() {
        return dateTimeNow(YYYYMMDDHHMMSS);
    }

    public static String dateTimeNow(final String format) {
        return parseDateToStr(format, new Date());
    }

    public static String dateTime(final Date date) {
        return parseDateToStr(YYYY_MM_DD, date);
    }

    public static String parseDateToStr(final String format, final Date date) {
        return new SimpleDateFormat(format).format(date);
    }

    public static Date dateTime(final String format, final String ts) {
        try {
            return new SimpleDateFormat(format).parse(ts);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 日期路径 即年/月/日 如2018/08/08
     */
    public static String datePath() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyy/MM/dd");
    }

    /**
     * 日期路径 即年/月/日 如20180808
     */
    public static String dateTime() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyyMMdd");
    }

    /**
     * 日期型字符串转化为日期 格式
     */
    public static Date parseDate(Object str) {
        if (str == null) {
            return null;
        }
        try {
            return parseDate(str.toString(), PARSE_PATTERNS);
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * 获取服务器启动时间
     */
    public static Date getServerStartDate() {
        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
        return new Date(time);
    }

    /**
     * 计算两个时间差
     */
    public static String getDatePoor(Date endDate, Date nowDate) {
        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        // long ns = 1000;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime() - nowDate.getTime();
        // 计算差多少天
        long day = diff / nd;
        // 计算差多少小时
        long hour = diff % nd / nh;
        // 计算差多少分钟
        long min = diff % nd % nh / nm;
        // 计算差多少秒//输出结果
        // long sec = diff % nd % nh % nm / ns;
        return day + "天" + hour + "小时" + min + "分钟";
    }


    /**
     * 增加 LocalDateTime ==> Date
     */
    public static Date toDate(LocalDateTime temporalAccessor) {
        ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());
        return Date.from(zdt.toInstant());
    }

    /**
     * 增加 LocalDate ==> Date
     */
    public static Date toDate(LocalDate temporalAccessor) {
        LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));
        ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
        return Date.from(zdt.toInstant());
    }

    /**
     * 通过传入月份获得开始时间和结束时间
     * 如果月份为空 使用当年作为时间范围
     *
     * @param year  年份
     * @param month 月份
     * @return 起始日期
     */
    public static Date[] getDateRange(Integer year, Integer month) {
        year = year == null ? DateUtil.year(new Date()) : year;
        Date beginDate, endDate;
        if (month != null) {
            beginDate = DateUtil.beginOfDay(DateUtil.parseDate(year + "-" + (month < 10 ? "0" + month : month) + "-01"));
            endDate = DateUtil.endOfMonth(beginDate);
        } else {
            beginDate = DateUtil.beginOfDay(DateUtil.parseDate(year + "-01-01"));
            endDate = DateUtil.endOfDay(DateUtil.parseDate(year + "-12-31"));
        }
        return new Date[]{beginDate, endDate};
    }

    /**
     * 通过传入月份获得开始时间和结束时间
     * 如果月份为空 使用当年作为时间范围
     *
     * @param year  年份
     * @param month 月份
     * @return 起始日期
     */
    public static Date[] getDateRangeUtilNow(Integer year, Integer month) {
        Date[] dateRange = getDateRange(year, month);
        if (month == null) {
            Date endOfMonth = DateUtil.endOfMonth(new Date());
            dateRange[1] = dateRange[1].after(endOfMonth) ? endOfMonth : dateRange[1];
        }
        return dateRange;
    }

    /**
     * 获取同比时间
     * @param year
     * @return
     */
    public static Map<String, Date[]> calculateComparisonDateRange(Integer year) {
        Date[] currentYearRange = getDateRange(year, null); // 获取当前年份的日期范围
        Date[] lastYearRange = getDateRange(year - 1, null); // 获取上一年的日期范围

        Date[] yearOnYearRange = {lastYearRange[0], lastYearRange[1]}; // 同比时间范围
        Date[] monthOnMonthRange = {currentYearRange[0], currentYearRange[1]}; // 环比时间范围

        // 对同比时间范围进行处理，确保不超过上一年的最后一天
        if (yearOnYearRange[1].after(lastYearRange[1])) {
            yearOnYearRange[1] = lastYearRange[1];
        }

        Map<String, Date[]> comparisonDateRange = new HashMap<>();
        comparisonDateRange.put("yearOnYear", yearOnYearRange);
        comparisonDateRange.put("monthOnMonth", monthOnMonthRange);

        return comparisonDateRange;
    }

    /**
     * 获取环比时间
     * @param startDate
     * @param endDate
     * @return
     */
    public static Date[] getMoMDateRange(Date startDate, Date endDate) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startDate);
        calendar.add(Calendar.MONTH, -1);
        Date lastMonthStartDate = calendar.getTime();

        calendar.setTime(endDate);
        calendar.add(Calendar.MONTH, -1);
        Date lastMonthEndDate = calendar.getTime();

        return new Date[]{lastMonthStartDate, lastMonthEndDate};
    }


    /**
     *  比较时间打大小
     * @param startTime 开始时间
     * @param endDate 结束时间
     * @return true OR false
     */
    public static boolean checkDate(Date startTime,Date endDate) {
        boolean isMember = false;
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(YYYY_MM_DD_HH_MM_SS);
            if (sdf.parse(sdf.format(startTime)).compareTo(endDate) <= 0) {
                isMember = true;
            }
        }catch (ParseException e){
            throw new RuntimeException(e);
        }
        return isMember;
    }

    /**
     *  获取上月第一天和最后一天
     * @param month 本月往前推几个月，默认null 为上月
     * @return 月第一天和最后一天
     */
    public static LocalDate[] getFirstLast(Integer month) {
        LocalDate date = LocalDate.now();
        if(month == null){
            month = 1;
        }
        date = date.minusMonths(month);
        LocalDate Last = date.with(TemporalAdjusters.lastDayOfMonth());
        LocalDate First = date.with(TemporalAdjusters.firstDayOfMonth());
        return new LocalDate[]{Last, First};
    }

    /**
     * 获取上个月
     * @param date yyyy-MM
     * @param n 输出指定日期的上一个月，如果是-1则代表数据下一个月
     * @return
     * @throws ParseException
     */
    public static String[] getLastMonth(String date,int n)  {
        Date dates= null;
        try {
            dates = new SimpleDateFormat("yyyy-MM-dd").parse(date);
        }catch (ParseException e){
            throw new RuntimeException(e);
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(dates);
        calendar.add(Calendar.MONTH, -n);
//        calendar.add(Calendar.MONTH, -n);
        return new String[]{new SimpleDateFormat("yyyy-M").format(calendar.getTime()),new SimpleDateFormat("yyyy").format(calendar.getTime()),new SimpleDateFormat("M").format(calendar.getTime())};
    }

    /**
     * 获取当前时间所在当前年的第几周，如果1月1日在周日，也算一周
     * @param date
     * @return
     */
    public static int getWeekNum(Date date) {
        GregorianCalendar g = new GregorianCalendar();
        g.setTime(date);
        return g.get(Calendar.WEEK_OF_YEAR); //获得周数
    }

    /**
     * 获取当前时间所在月有多少天
     * @param date
     * @return
     */
    public static int getDaysOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
    }


    /**
     * 获取当前周的周一和周末
     *
     * @param n      -1代表上一周 +1代表下一周 0代表当前周
     * @param myDate 当前日期
     */
    public static Date[] getweek(int n, Date myDate) {
//        List<Date> date = new ArrayList<Date>();

        Date beginDate, endDate = null, YearSameBeginDate, YearSameEndDate = null;
        try {
            Calendar calendar = Calendar.getInstance();
            calendar.setFirstDayOfWeek(Calendar.MONDAY);
            Calendar cal = Calendar.getInstance();
            cal.setTime(myDate);
            //判断要计算的日期是否是周日，如果是则减一天计算周六的，否则会出问题，计算到下一周了
            int dayWeek = cal.get(Calendar.DAY_OF_WEEK);//获得当前日期是一个星期的第几天
            if (1 == dayWeek) {
                cal.add(Calendar.DAY_OF_MONTH, -1);
            }
            //设置一个星期的第一天，按中国的习惯一个星期的第一天是星期一
            cal.setFirstDayOfWeek(Calendar.MONDAY);
            //获得当前日期是一个星期的第几天
            int day = cal.get(Calendar.DAY_OF_WEEK);
            //根据日历的规则，给当前日期减去星期几与一个星期第一天的差值
            cal.add(Calendar.DATE, (cal.getFirstDayOfWeek() - day + 7 * n));

            beginDate = cal.getTime();

            cal.add(Calendar.DATE, 6);

            endDate = cal.getTime();

            cal.add(Calendar.YEAR, -1);
            YearSameEndDate = cal.getTime();
            cal.add(Calendar.DATE, -6);
            YearSameBeginDate = cal.getTime();


        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        return new Date[]{beginDate, endDate, YearSameBeginDate, YearSameEndDate};
    }

    /**
     * 获取当前时间是本周、本月、本年的第几天
     * @return
     */
    public static Integer[] yearMonthWeek(){
        Calendar calendar = Calendar.getInstance();
        //时间，可以为具体的某一时间
        Date today = new Date();
        calendar.setTime(today);
        int weekDay = calendar.get(Calendar.DAY_OF_WEEK);
        int monthDay = calendar.get(Calendar.DAY_OF_MONTH);
        int yearDay = calendar.get(Calendar.DAY_OF_YEAR);
        if (weekDay == 1) {
            weekDay = 7;
        } else {
            weekDay = weekDay - 1;
        }
        return new Integer[] {yearDay,monthDay,weekDay};
    }

    /**
     * 根据传入的日期返回同比时间，例如传入2023-3-31
     * 则返回2022-3-31 和2022-1-1
     * @param date
     * @return
     */
    public static Date[] getYOY(Date date){

        Calendar start= Calendar.getInstance();
        start.setTime(date);

        start.add(Calendar.YEAR, -1);
        int dateYear = start.get(Calendar.YEAR);
        int dateMonth = start.get(Calendar.MONTH)+1;
        Date lastYearEndDate = start.getTime(); //去年今日
        Date lastYearBeginDate = DateUtil.beginOfDay(DateUtil.parseDate(dateYear + "-01-01"));//去年第一天
        Date lastYearMonthBeginDate = DateUtil.beginOfDay(DateUtil.parseDate(dateYear + "-" + (dateMonth < 10 ? "0" + dateMonth : dateMonth) + "-01"));//去年本月第一天
        Date[] dateRange = getDateRange(null, dateMonth);
        return new Date[]{lastYearBeginDate,lastYearEndDate,lastYearMonthBeginDate,lastYearEndDate,dateRange[0],date};
        //去年第一天,去年今日,去年本月第一天,去年本月今日,当前年本月第一天，当前年今日
    }

    public static String[] getMonthDays(String strDate) {
        LocalDate date = LocalDate.parse(strDate + "-01"); // 将日期字符串转换为LocalDate类型，并将日设置为1
        int days = date.lengthOfMonth(); // 获取指定月份的天数
        List<String> dayList = new ArrayList<>();
        for (int i = 1; i <= days; i++) {
            LocalDate tempDate = date.withDayOfMonth(i); // 获取当前循环的日期
            String day = tempDate.toString(); // 将日期转换为字符串
            dayList.add(day);
        }
        String[] result = new String[dayList.size()];
        return dayList.toArray(result);
    }
    public static String[] getMonthFirstAndLastDays(String strDate) {
        LocalDate date = LocalDate.parse(strDate + "-01");
        String firstDay = date.withDayOfMonth(1).toString(); // 获取当月的第一天
        String lastDay = date.withDayOfMonth(date.lengthOfMonth()).toString(); // 获取当月的最后一天
        return new String[]{firstDay, lastDay};
    }

    /**
     * 获取去年本月的最后一天和上个月的最后一天
     * @param dates
     * @return
     */
    public static LocalDate[] getLastDaysOfLastYearAndLastMonth(LocalDate... dates) {
        LocalDate date = (dates.length > 0) ? dates[0] : LocalDate.now();

        YearMonth currentYearMonth = YearMonth.from(date);

        YearMonth lastYearMonth = currentYearMonth.minusYears(1);
        int lastYearMonthLastDay = lastYearMonth.lengthOfMonth();

        int lastMonthLastDay = currentYearMonth.minusMonths(1).lengthOfMonth();
        LocalDate localDate = lastYearMonth.atDay(lastYearMonthLastDay);
        System.out.println("去年本月的最后一天：" + lastYearMonth.atDay(lastYearMonthLastDay));
        System.out.println("上个月的最后一天：" + currentYearMonth.minusMonths(1).atDay(lastMonthLastDay));
        return new LocalDate[]{lastYearMonth.atDay(lastYearMonthLastDay),currentYearMonth.minusMonths(1).atDay(lastMonthLastDay)};
    }
}
